#include "HSocket.h"

HSocket::HSocket(int flag)
{
    s = -5;
    this->flag = flag;
}

int HSocket::HGetSocket()
{
    switch (flag)
    {
    case IPV6|TCP:
        s = socket(AF_INET6, SOCK_STREAM, 0);
    break;
    case IPV4|TCP:
        s = socket(AF_INET, SOCK_STREAM, 0);
        break;
    case IPV4|UDP:
        s = socket(AF_INET, SOCK_DGRAM, 0);
        break;
    default:
        break;
    }
    if (s == -1) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif //  Win
        cout << "socket failed!" << endl;
        return -1;
    }
    cout << "get Socket successfully!" << endl;
    return s;
}

void HSocket::Hclose()
{
    if (s == -1) return;
    else {
#ifdef _WIN32
        closesocket(s);
#else
        close(s);
#endif // Win

    }
}

HSocket::~HSocket()
{
    Hclose();
}

int HSocket::Hbind(const sockaddr_in6& add)
{
    HGetSocket();
    if (bind(s, (sockaddr*)&add, sizeof(add)) == -1) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif //  Win
        cout << "bind failed!" << endl;
        Hclose();
        return -1;
    }
    cout << "bind Socket successfully!" << endl;
    this->add = add;
    return 0;
}

int HSocket::Hbind(const sockaddr_in add)
{
    HGetSocket();
    if (bind(s, (sockaddr*)&add, sizeof(add)) == -1) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif //  Win
        cout << "bind failed!" << endl;
        Hclose();
        return -1;
    }
    cout << "bind Socket successfully!" << endl;
    this->add4 = add4;
    return 0;
}

int HSocket::Hlisten(int backlog)
{
    if (listen(s, 5) == -1) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif 
        cout << "listen failed!" << endl;
        Hclose();
        return -1;
    }
    cout << "Socket listen successfully!" << endl;
    return 0;
}

SOCKET HSocket::Haccept()
{
    sockaddr_in6 cli;
    sockaddr_in cli4;
#ifdef _WIN32
    int len = sizeof(cli);
#else
    socklen_t len = sizeof(cli);
#endif // Win
    cout << "wait connect....." << endl;
    SOCKET clentSocket;
    if (flag & IPV6) {
        clentSocket = accept(s, (sockaddr*)&cli, &len);
    }
    else {
        clentSocket = accept(s, (sockaddr*)&cli4, &len);
    }
    if (clentSocket == -1) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif 
        cout << "accept failed!" << endl;
        Hclose();
        return -1;
    }
    //打印客户端信息
    char clientIp[1024];
    if (flag & IPV6) {
        inet_ntop(AF_INET6, &(cli.sin6_addr), clientIp, 1024);
        cout << "Client connect!\nip:" << clientIp << "\nport:" << ntohs(cli.sin6_port) << endl;
    }
    else {
        inet_ntop(AF_INET, &(cli4.sin_addr), clientIp, INET_ADDRSTRLEN);
        std::cout << "Client connected from: " << clientIp << ", Port: " << ntohs(cli4.sin_port) << std::endl;
    }
    return clentSocket;
}

int HSocket::Hconnect(const sockaddr_in6& add)
{
    if (connect(s, (sockaddr*)&add, sizeof(add))) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif 
        cout << "connect failed!" << endl;
        Hclose();
        return -1;
    }
    cout << "connect successfully!" << endl;
    return 0;
}

int HSocket::Hconnect(const sockaddr_in& add)
{
    if (connect(s, (sockaddr*)&add, sizeof(add))) {
#ifdef  _WIN32
        cout << "error:" << WSAGetLastError() << endl;
#endif 
        cout << "connect failed!" << endl;
        Hclose();
        return -1;
    }
    cout << "connect successfully!" << endl;
    return 0;
}

Common::Common(int flag)
{
    this->flag = flag;
#ifdef _WIN32
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        exit(0);
        cout << "Failed to initialize winsock" << endl;
        return;
    }
#endif // Win
    sock = new HSocket(flag);
}

Common::~Common()
{
#ifdef _WIN32
    WSACleanup();
#endif
    delete sock;
}

int Common::recvData(string& data,SOCKET s)
{
    data.clear();
    char* buf = new char[MAX_SIZE];
    rcvlock.lock();
    int ret = recv(s, buf, MAX_SIZE, 0);
    rcvlock.unlock();
    if (ret < 0) {
        cout << "recv error!" << endl;
        return -1;
    }
    cout<<"recv size:"<<ret<<endl;
    data = string(buf,ret);
    return ret;
}

int Common::recvData(string& data, SOCKET s, sockaddr_in& cliAdd)
{
    data.clear();
    char* buf = new char[MAX_SIZE];
#ifdef _WIN32
    int len = sizeof(sockaddr_in);
#else
    socklen_t len = sizeof(sockaddr_in);
#endif // _WIN32
    rcvlock.lock();
    int ret = recvfrom(s, buf, MAX_SIZE, 0, (sockaddr*)&cliAdd,&len);
    rcvlock.unlock();
    if (ret < 0) {
        cout << "recv error!" << endl;
        return -1;
    }
    //cout << "recv size:" << ret << endl;
    data = string(buf,ret);
    return ret;
}

int Common::recvData(string& data, SOCKET s, sockaddr_in6& cliAdd)
{
    data.clear();
    char* buf = new char[MAX_SIZE];
#ifdef _WIN32
    int len = sizeof(sockaddr_in6);
#else
    socklen_t len = sizeof(sockaddr_in6);
#endif // _WIN32
    rcvlock.lock();
    int ret = recvfrom(s, buf, 4096, 0, (sockaddr*)&cliAdd, &len);
    rcvlock.unlock();
    if (ret < 0) {
        cout << "recv error!" << endl;
        return -1;
    }
    //cout << "recv size:" << ret << endl;
    data = string(buf,ret);
    return ret;
}

int Common::sendData(const string& data, SOCKET s)
{
    sendlock.lock();
    int ret = send(s, data.c_str(), data.size(), 0);
    sendlock.unlock();
    if (ret < 0) {
        cout << "send error!" << endl;
        return -1;
    }
    return ret;
}

int Common::sendData(const string& data, SOCKET s, const sockaddr_in& add)
{
    sendlock.lock();
    int ret = sendto(s, data.c_str(),data.size(),0, (sockaddr*)&add, sizeof(sockaddr_in));
    sendlock.unlock();
    if (ret < 0) {
        cout << "send error!" << endl;
        return -1;
    }
    return ret;
}

int Common::sendData(const string& data, SOCKET s, const sockaddr_in6& add)
{
    sendlock.lock();
    int ret = sendto(s, data.c_str(), data.size(), 0, (sockaddr*)&add, sizeof(sockaddr_in6));
    sendlock.unlock();
    if (ret < 0) {
        cout << "send error!" << endl;
        return -1;
    }
    return ret;
}

HServerBase::HServerBase(int flag):
    Common(flag)
{
    this->status = 0;
}

HServerBase::~HServerBase()
{
}

int HServerBase::initServer(const u_short& port, int backlog)
{
    sockaddr_in6 serverAdd{};
    sockaddr_in serverAdd4{};
    if (flag & IPV6) {
        memset(&serverAdd, 0, sizeof(serverAdd));
        serverAdd.sin6_family = AF_INET6;
        serverAdd.sin6_port = htons(port);
        serverAdd.sin6_addr = in6addr_any;
        if (sock->Hbind(serverAdd) == -1) return -1;
    }
    else {
        memset(&serverAdd4, 0, sizeof(serverAdd4));
        serverAdd4.sin_family = AF_INET;
        serverAdd4.sin_addr.s_addr = INADDR_ANY;
        serverAdd4.sin_port = htons(port);
        if (sock->Hbind(serverAdd4) == -1) return -1;
    }
    if (flag & TCP) {
        if (sock->Hlisten(backlog) == -1) return -1;
    }
    return 0;
}

int HServerBase::startServer()
{
    status = 1;
    while (status) {
        SOCKET cli = sock->Haccept();
        if (cli == -1) return -1;
    }
    return 0;
}

void HServerBase::stopServer()
{
    status = 0;
}

HClientBase::HClientBase(int flag) :
    Common(flag)
{
    memset(&serverAdd,0,sizeof(serverAdd));
}

HClientBase::~HClientBase()
{
}

int HClientBase::initClient(const char* ip, u_short port)
{
    sock->HGetSocket();
    if (flag & IPV6) {
        serverAdd.sin6_family = AF_INET6;
        serverAdd.sin6_port = htons(port);
        serverAdd.sin6_addr = in6addr_any;
        #ifdef _Win32
        int charStrLen = static_cast<int>(strlen(ip) + 1);
        int wcharStrLen = MultiByteToWideChar(CP_UTF8, 0, ip, charStrLen, nullptr, 0);
        wchar_t* wcharStr = new wchar_t[wcharStrLen];
        MultiByteToWideChar(CP_UTF8, 0, ip, charStrLen, wcharStr, wcharStrLen);
        int ret = InetPton(AF_INET6, wcharStr, &(serverAdd.sin6_addr));
        delete[] wcharStr;
        #else
        int ret = inet_pton(AF_INET6,ip,&(serverAdd.sin6_addr));
        #endif
        if (ret != 1) {
            #ifdef _Win32
            cout << "error:" << WSAGetLastError() << endl;
            #endif
            cout << "InetPton failed!" << endl;
            return -1;
        }
    }
    else {
        serverAdd4.sin_family = AF_INET;
        serverAdd4.sin_addr.s_addr = inet_addr(ip); // 设置服务器IPv4地址
        serverAdd4.sin_port = htons(port); // 设置服务器端口
    }
    return 0;
}

int HClientBase::startClient()
{
    if (sock->Hconnect(serverAdd) == -1) return -1;
    //客户端逻辑
    return 0;
}
